package ge.scenes;

import ge.engine.Engine;
import ge.engine.Rule;

import java.util.ArrayList;

/**
 * 
 * @author Abel
 * A Scene is the director of one or more traks associateds.
 */
public class Scene implements Rule {

	private ArrayList<Track> tracks;
	private boolean advance;
	private SceneMode mode;
	private double duration;
	private double actualTime;
	private boolean playing;
	 
	/**
	 * 	Constructs a new scene
	 * @param milliseconds The duration of the scene in milliseconds
	 */
	public Scene(double milliseconds)
	{
		tracks = new ArrayList<Track>();
		advance = true;
		this.duration = milliseconds;
		actualTime = 0f;
		playing = false;
	}
	

	/**
	 * 	
	 * @param track Adds a new Track
	 */
	public void addTrack(Track track)
	{
		tracks.add(track);
	}
	/**
	 * 	
	 * @param track Remove the track of the scene
	 */
	public void removeTrack(Track track)
	{
		tracks.remove(track);
	}
	@Override
	public void update() 
	{
		if(!playing )	 
			return;
		//Update the time
		actualTime+=(advance?Engine.tick():-Engine.tick());
		
		
		if(actualTime >= 0 && actualTime < duration)
		{
			for(Track t : tracks)
			{
				if(advance)
					t.advance(actualTime);
				else
					t.reverse(actualTime);
			}
		}
		else
		{
			loopLogic();	//Makes differents things depending the mode
		}
		
	}
	/**
	 * 	Knows how to loop
	 */
	private void loopLogic()
	{
		//Reached end
		if(actualTime >= duration)
		{
			switch(mode)
			{
				case PlayAndReverse:
				case PlayAndReverseLooped:
					reverse();
					break;
				case PlayLooped:
					play();
					break;
				default:
					stop();
					
			}
			
		}
		else	//Reached beginning
		{
			switch(mode)
			{
				case PlayAndReverseLooped:
					play();
					break;
				case ReverseLoop:
					reverse();
					break;
				default:
					stop();
			}
		}
		
	}

	/**
	 * @return The actual SceneMode
	 */
	public SceneMode getMode() 
	{
		return mode;
	}
	/**
	 *  Sets the scene mode, it will indicate different kinds
	 *  of loops. By default is NoLoop mode
	 *  
	 *  
	 * @param mode
	 */
	public void setMode(SceneMode mode) 
	{
		this.mode = mode;
	}
	
	/**
	 * 	Plays the scene since the time.
	 * 	Plays it forward
	 * @param time Time to start
	 */
	public void play(double time)
	{
		advance = true;
		setCurrentTime(time);
		playing = true;
		for (Track t : tracks) {
			t.currentTimeJump(time, true);
		}
	}
	
	 
	/**
	 * 	Resumes the play in the same direction it was stopped.
	 */
	public void resume()
	{
		playing = true;	 
	}
	/**
	 * 	Play the scene since the beginning
	 */
	public void play()
	{
		play(0);
	}
	/**
	 * 	Plays the scene since the time.
	 * 	Plays it backward
	 * @param time Time to start
	 */
	public void reverse(double time)
	{
		advance = false;
		setCurrentTime(time);
		playing = true;
	
	}
	/**
	 * Plays it backward since the end
	 */
	public void reverse()
	{
		reverse(duration-0.001);
	}
	/**
	 * 	Modify the actual time. Scene will continue doing
	 * 	what its doing. Time won't never be less than 0 or greater
	 * 	than duration.
	 * @param time Actual time
	 */
	public void setCurrentTime(double time)
	{
		actualTime = Math.max(Math.min(duration, time), 0);
		for (Track t : tracks) {
			t.currentTimeJump(actualTime, advance);
		}
	}
	/**
	 * 
	 * @return The scene current's time
	 */
	public double getCurrentTime()
	{
		return actualTime;
	}
	/**
	 * 	Stops the Scene, and carries the time to the beginning
	 */
	public void stop()
	{
		actualTime = 0;
		playing = false;
		
	}
	/**
	 * Pauses the scene, the actual time don't change
	 */
	public void pause()
	{
		playing = false;
	}
	/**
	 * @return The temporal size of the scene.
	 */
	public double getDuration()
	{
		return duration;
	}
	/**
	 * 
	 * @return If the scene is now been playing
	 */
	public boolean isPlaying()
	{
		return playing;
	}
}
